﻿using System;
using System.Collections.Generic;
using System.DirectoryServices;
using System.Linq;
using JQuery.WebKit.Common.Caching;

namespace JQuery.WebKit.Common.ActiveDirectory
{
    [Serializable]
    public abstract class ADObject
    {
        #region protected Principal _objectPrincipal
        /// <summary>
        /// Get/Sets the _objectPrincipal of the <see cref="Common.ActiveDirectory.ADObject"/>
        /// </summary>
        //protected Principal _objectPrincipal;
        #endregion

        

        private string _name;
        #region public string Name
        /// <summary>
        /// Get/Sets the Name of the ADObject
        /// </summary>
        /// <value></value>
        public string Name
        {
            get { return _name; }
            set { _name = value; }
        }
        #endregion

        private string _displayName;
        #region public string DisplayName
        /// <summary>
        /// Get/Sets the DisplayName of the ADObject
        /// </summary>
        /// <value></value>
        public string DisplayName
        {
            get { return _displayName; }
            set { _displayName = value; }
        }
        #endregion

        public string DistinguishedName
        {
            get;
            private set;
        }

        #region public object Tag
        /// <summary>
        /// Get/Sets the Tag of the ADObject
        /// </summary>
        /// <value></value>
        public object Tag
        {
            get;
            set;
        }
        #endregion

        private ADContextType _contextType;
        #region public ADContextType ContextType
        /// <summary>
        /// Get/Sets the ContextType of the ADObject
        /// </summary>
        /// <value></value>
        public ADContextType ContextType
        {
            get { return _contextType; }
            set { _contextType = value; }
        }
        #endregion

        #region public abstract ADObjectType ObjectType
        /// <summary>
        /// Gets the ObjectType of the ADObject
        /// </summary>
        /// <value></value>
        public abstract ADObjectType ObjectType
        {
            get;
        }
        #endregion

        #region public ADObject()
        /// <summary>
        /// Initializes a new instance of the <b>ADObject</b> class.
        /// </summary>
        public ADObject()
            : this(string.Empty, ADContextType.Unknown, null)
        {

        }
        #endregion

        #region public ADObject(string name, ADContextType contextType, Principal objectPrincipal)
        /// <summary>
        /// Initializes a new instance of the <b>ADObject</b> class.
        /// </summary>
        /// <param name="name"></param>
        /// <param name="contextType"></param>
        /// <param name="objectPrincipal"></param>
        public ADObject(string name, ADContextType contextType, string distinguishedName)
        {
            _name = name;
            _contextType = contextType;
            DistinguishedName = distinguishedName;
            //_objectPrincipal = objectPrincipal;
        }
        #endregion

        #region public IList<GroupInfo> GetGroups()
        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        public IList<GroupInfo> GetGroups(bool refreshCache)
        {
            return GetGroups(ContextType, refreshCache);
        }
        #endregion

        #region public IList<GroupInfo> GetGroups(ADContextType contextType)
        /// <summary>
        /// 
        /// </summary>
        /// <param name="contextType"></param>
        /// <returns></returns>
        public IList<GroupInfo> GetGroups(ADContextType contextType, bool refreshCache)
        {
            //IList<GroupInfo> _groups = null;
            //if (_groups != null)
            //{
            //    return _groups;
            //}
            IList<GroupInfo> _groups = (List<GroupInfo>)Cache.Current.GetItem(string.Format("ADObject_{0}_{1}", DistinguishedName, contextType));
            if (_groups != null && !refreshCache)
            {
                return _groups;
            }
            _groups = new List<GroupInfo>();
            DirectorySearcher src = new DirectorySearcher("(objectCategory=group)");
            foreach (SearchResult res in src.FindAll())
            {
                ResultPropertyValueCollection member = (ResultPropertyValueCollection)res.Properties["member"];
                if (member == null)
                {
                    continue;   
                }
                if (!member.Contains(DistinguishedName))
                {
                    continue;
                }
                using (DirectoryEntry ent = res.GetDirectoryEntry())
                {
                    _groups.Add(GroupInfo.GetGroupInfo(ent, ContextType));
                }
            }

            Cache.Current.RemoveItem(string.Format("ADObject_{0}_{1}", DistinguishedName, contextType));
            Cache.Current.AddItem(string.Format("ADObject_{0}_{1}", DistinguishedName, contextType), _groups);

            return _groups;
        }
        #endregion

        public bool IsMemberOf(string groupName, bool refreshGroups)
        {
            return IsMemberOf(groupName, ContextType, refreshGroups);
        }

        public bool IsMemberOf(string groupName, ADContextType contextType, bool refreshGroups)
        {
            IList<GroupInfo> groups = this.GetGroups(contextType, refreshGroups);
            return groups.Count<GroupInfo>(item => item.Name == groupName) > 0;
        }
    }
}
